//-------------------------------------------------------------------------------------
//
// Copyright 2009 Intel Corporation
// All Rights Reserved
//
// Permission is granted to use, copy, distribute and prepare derivative works of this
// software for any purpose and without fee, provided, that the above copyright notice
// and this statement appear in all copies.  Intel makes no representations about the
// suitability of this software for any purpose.  THIS SOFTWARE IS PROVIDED "AS IS."
// INTEL SPECIFICALLY DISCLAIMS ALL WARRANTIES, EXPRESS OR IMPLIED, AND ALL LIABILITY,
// INCLUDING CONSEQUENTIAL AND OTHER INDIRECT DAMAGES, FOR THE USE OF THIS SOFTWARE,
// INCLUDING LIABILITY FOR INFRINGEMENT OF ANY PROPRIETARY RIGHTS, AND INCLUDING THE
// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.  Intel does not
// assume any responsibility for any errors which may appear in this software nor any
// responsibility to update it.
//

#ifndef _NULSTEIN_MUTEX_H_
#define _NULSTEIN_MUTEX_H_

#include "Defines.h"

//________________________________________________________________________________
#if 0
class CSpinMutex
{
public:
	CSpinMutex() 
	{
		InitializeCriticalSectionAndSpinCount(&cs, 4000);
	}

	void Lock() 
	{
		while (!TryLock()) {;}
	}
	
	bool TryLock()
	{
		return FALSE!=TryEnterCriticalSection(&cs);
	}
	
	void Unlock()
	{
		LeaveCriticalSection(&cs);
	}

public:
	CRITICAL_SECTION cs;
};
#else
class CACHELINE_ALIGNED CSpinMutex
{
public:
	CSpinMutex() {m_Locked = 0;}

	void Lock() 
	{
		while (!TryLock()) {;}
	}
	
	bool TryLock()
	{
		return InterlockedExchange(&m_Locked, 1) == 0;
	}
	
	void Unlock()
	{
		InterlockedExchange(&m_Locked, 0);
	}

public:
	volatile LONG m_Locked;
	/* uses all of cache line to avoid false sharing */ 
    char padding[12];
};
#endif

//________________________________________________________________________________
class CSpinMutexLock
{
public:
	CSpinMutexLock() 
	{
		m_pMutex = NULL;
	}
	
	CSpinMutexLock(CSpinMutex* pMutex, bool bLock = true)
	{
		m_pMutex = pMutex;
		if (bLock) m_pMutex->Lock();
	}
	
	bool TryLock(CSpinMutex* pMutex)
	{
		if (!pMutex->TryLock()) 
			return false;
			
		m_pMutex = pMutex;
		return true;
	}

	~CSpinMutexLock()
	{
		if (m_pMutex) 
			m_pMutex->Unlock();
	}

public:
	CSpinMutex*	m_pMutex;
};


#endif // _NULSTEIN_MUTEX_H_